package middleware

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v5"
	"net/http"
	"new_ginblog/internal/utils/errormsg"
	"strings"
	"time"
)

const (
	AccessTokenSecret  = "access_token_secret"
	RefreshTokenSecret = "refresh_token_secret"
)

// MyCustomClaims 自定义结构体
type MyCustomClaims struct {
	Username string `json:"username"`
	jwt.RegisteredClaims
}

// SetAccessToken 生成AccessToken 短期token
func SetAccessToken(username string) (string, int) {
	//过期时间
	accessExpireTime := jwt.NewNumericDate(time.Now().Add(time.Minute * 1))
	SetClaims := MyCustomClaims{
		username,
		jwt.RegisteredClaims{
			ExpiresAt: accessExpireTime,               // 过期时间
			Issuer:    "ginBlog",                      // 签发人
			IssuedAt:  jwt.NewNumericDate(time.Now()), //签发时间
		},
	}

	// 使用HS2签名方法
	reqClaim := jwt.NewWithClaims(jwt.SigningMethodHS256, SetClaims)
	token, err := reqClaim.SignedString([]byte(AccessTokenSecret))
	if err != nil {
		return "", errormsg.ERROR
	}
	return token, errormsg.SUCCESS
}

// SetRefreshToken 生成RefreshToken 长期token
func SetRefreshToken(username string) (string, int) {
	refreshExpireTime := jwt.NewNumericDate(time.Now().Add(time.Hour * 1))
	SetClaims := MyCustomClaims{
		username,
		jwt.RegisteredClaims{
			ExpiresAt: refreshExpireTime,
			Issuer:    "ginBlog",
			IssuedAt:  jwt.NewNumericDate(time.Now()),
		},
	}
	reqClaim := jwt.NewWithClaims(jwt.SigningMethodHS256, SetClaims)
	token, err := reqClaim.SignedString([]byte(RefreshTokenSecret))
	if err != nil {
		return "", errormsg.ERROR
	}
	return token, errormsg.SUCCESS
}

// CheckAccessToken 验证短期token
func CheckAccessToken(token string) (*MyCustomClaims, int) {
	// 解析token并验证签名
	tokenObj, err := jwt.ParseWithClaims(token, &MyCustomClaims{}, func(token *jwt.Token) (interface{}, error) {
		// 验证token签名方式是否为hs256
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
		}
		return []byte(AccessTokenSecret), nil
	})

	// 处理错误
	if err != nil {
		return nil, errormsg.ERROR
	}

	// 验证token有效性并提取claims
	if claims, ok := tokenObj.Claims.(*MyCustomClaims); ok && tokenObj.Valid {
		return claims, errormsg.SUCCESS
	}
	return nil, errormsg.ERROR
}

// CheckRefreshToken 验证长期token
func CheckRefreshToken(token string) (*MyCustomClaims, int) {
	// 解析token并验证签名
	tokenObj, err := jwt.ParseWithClaims(token, &MyCustomClaims{}, func(token *jwt.Token) (interface{}, error) {
		// 验证token签名方式是否为hs256
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
		}
		return []byte(RefreshTokenSecret), nil
	})

	// 处理错误
	if err != nil {
		return nil, errormsg.ERROR
	}

	// 验证token有效性并提取claims
	if claims, ok := tokenObj.Claims.(*MyCustomClaims); ok && tokenObj.Valid {
		return claims, errormsg.SUCCESS
	}
	return nil, errormsg.ERROR
}

// JwtAccessToken jwt中间件、
func JwtAccessToken() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 从请求头里面提取 Authorization 字段
		// 约定 jwt 一般会放在请求头
		tokenHeader := c.Request.Header.Get("token")
		code := errormsg.SUCCESS // 初始化一个状态码 返回数据时使用
		if tokenHeader == "" {
			code = errormsg.ERROR_TOKEN_NOT_EXIST
			c.JSON(http.StatusOK, gin.H{
				"code": code,
				"msg":  errormsg.GetErrorMsg(code),
			})
			c.Abort()
			return
		}

		//将 Authorization 拆分成两部分（前缀 + token 值）。
		//如果格式不符合 Bearer <token>，就返回 ERROR_TOKEN_TYPE_WRONG。
		checkToken := strings.SplitN(tokenHeader, " ", 2)
		if len(checkToken) != 2 || checkToken[0] != "Bearer" {
			code = errormsg.ERROR_TOKEN_TYPE_WRONG
			c.JSON(http.StatusOK, gin.H{
				"code": code,
				"msg":  errormsg.GetErrorMsg(code),
			})
			c.Abort()
			return
		}

		key, tCode := CheckAccessToken(checkToken[1])
		if tCode != errormsg.SUCCESS {
			code = errormsg.ERROR_TOKEN_WRONG
			c.JSON(http.StatusOK, gin.H{
				"code": code,
				"msg":  errormsg.GetErrorMsg(code),
			})
			c.Abort()
			return
		}

		// 检查token是否过期
		if key.ExpiresAt != nil && key.ExpiresAt.Before(time.Now()) {
			code = errormsg.ERROR_ACCESS_TOKEN_RUNTIME
			c.JSON(http.StatusOK, gin.H{
				"code": code,
				"msg":  errormsg.GetErrorMsg(code),
			})
			c.Abort()
			return
		}

		c.Set("username", key.Username)
		c.Next()
	}
}

// JwtRefreshToken 中间件
func JwtRefreshToken() gin.HandlerFunc {
	return func(c *gin.Context) {

	}
}
